package org.df.ulab.util.crypto;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

/**
 * @author Daniel Filgueiras
 * @since 19/06/2011
 */
public class CryptoApi {

	private Cipher cipher;
	
	private CryptoApi(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException {
		cipher = Cipher.getInstance(transformation);
	}
	
	public static CryptoApi getInstanceAES() throws NoSuchAlgorithmException, NoSuchPaddingException {
		return new CryptoApi("AES");
	}
	public static CryptoApi getInstanceRSA() throws NoSuchAlgorithmException, NoSuchPaddingException {
		return new CryptoApi("RSA");
	}
	
	// Single Key
	public byte[] encrypt(Key key, byte[] secret) throws Exception {
		
		cipher.init(Cipher.ENCRYPT_MODE, key);
		return cipher.doFinal(secret);
	}
	
	public byte[] decrypy(Key key, byte[] encoded) throws Exception {
		cipher.init(Cipher.DECRYPT_MODE, key);
		return cipher.doFinal(encoded);
	}
	
	public Key getKeyAES(String key) throws Exception {

		Key keySpec = null;
		if (key == null) {
			keySpec = KeyGenerator.getInstance("AES").generateKey();
		} else {
			byte[] byteCode = new byte[16];
			byte[] rawKeyBC = key.getBytes();
			for (int c = 0; c < byteCode.length; c++) {
				if (c < rawKeyBC.length) {
					byteCode[c] = rawKeyBC[c];
				}
			}
			
			keySpec = new SecretKeySpec(byteCode, "AES");
		}
		return keySpec;
	}
	
	// Pair Key 
	public byte[] encrypt(KeyPair key, byte[] secret) throws Exception {
		cipher.init(Cipher.ENCRYPT_MODE, key.getPublic());
		return cipher.doFinal(secret);
	}
	
	public byte[] decrypy(KeyPair key, byte[] encoded) throws Exception {
		cipher.init(Cipher.DECRYPT_MODE, key.getPrivate());
		return cipher.doFinal(encoded);
	}
	
	public KeyPair getKeyPair() throws Exception {

		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
		generator.initialize(512);
		
		return generator.generateKeyPair();
	}
	
	public static PrivateKey getPrivateKey(byte[] encoded) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		EncodedKeySpec spec = new PKCS8EncodedKeySpec(encoded);
		return keyFactory.generatePrivate(spec);
	}
	
	public static void main(String[] args) throws Exception {
		CryptoApi api;
		
		// Single Key
		api = CryptoApi.getInstanceAES();
		
		String myKey = Long.toHexString(System.currentTimeMillis());
		Key key = api.getKeyAES(myKey);
		
		String secret = "Oi, tudo bem";
		
		byte[] encoded = api.encrypt(key, secret.getBytes());
		
		System.out.println("Encoded: " + new String(encoded));
		
		byte[] decoded = api.decrypy(key, encoded);
		
		System.out.println("Decoded: " + new String(decoded));
		
		// Pair Keys
		api = CryptoApi.getInstanceRSA();
		
		KeyPair keyPair = api.getKeyPair();
		
		encoded = api.encrypt(keyPair, secret.getBytes());
		
		System.out.println("Encoded: " + new String(encoded));
		
		decoded = api.decrypy(keyPair, encoded);
		
		System.out.println("Decoded: " + new String(decoded));
	}
}
